package org.hcyspartnoc.luoxin.service.system.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.hcyspartnoc.luoxin.common.core.PageBean;
import org.hcyspartnoc.luoxin.common.enums.system.SysPermissionStatusEnum;
import org.hcyspartnoc.luoxin.common.exception.system.SysPermissionException;
import org.hcyspartnoc.luoxin.common.exception.system.SysRoleException;
import org.hcyspartnoc.luoxin.mapper.system.SysPermissionMapper;
import org.hcyspartnoc.luoxin.mapper.system.SysRoleMapper;
import org.hcyspartnoc.luoxin.mapper.system.SysRolePermissionMapper;
import org.hcyspartnoc.luoxin.pojo.dto.system.SysPermissionBindingRoleDto;
import org.hcyspartnoc.luoxin.pojo.po.system.SysPermissionPo;
import org.hcyspartnoc.luoxin.pojo.po.system.SysRolePermissionPo;
import org.hcyspartnoc.luoxin.pojo.po.system.SysRolePo;
import org.hcyspartnoc.luoxin.pojo.vo.system.SysPermissionVo;
import org.hcyspartnoc.luoxin.service.system.ISysPermissionService;
import org.hcyspartnoc.luoxin.utils.redis.RedisComponent;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Service
public class SysPermissionServiceImpl extends ServiceImpl<SysPermissionMapper, SysPermissionPo> implements ISysPermissionService {
    @Resource
    private SysPermissionMapper sysPermissionMapper;
    @Resource
    private SysRoleMapper sysRoleMapper;
    @Resource
    private SysRolePermissionMapper sysRolePermissionMapper;
    @Resource
    private RedisComponent redisComponent;

    @Override
    public PageBean<SysPermissionPo, SysPermissionVo> queryByPage(Integer currentPage, Integer pageSize, String authCode, Integer status, Integer roleId) {
        MPJLambdaWrapper<SysPermissionPo> wrapper = new MPJLambdaWrapper<SysPermissionPo>()
                .leftJoin(SysRolePermissionPo.class, SysRolePermissionPo::getPermissionId, SysPermissionPo::getId)
                .like(!authCode.isEmpty(), SysPermissionPo::getAuthCode, authCode)
                .eq(status != 0, SysPermissionPo::getStatus, status)
                .eq(roleId != 0, SysRolePermissionPo::getRoleId, roleId)
                .selectAll(SysPermissionPo.class)
                .orderByAsc(SysPermissionPo::getId);
        Page<SysPermissionPo> page = new Page<>(currentPage, pageSize);
        sysPermissionMapper.selectPage(page, wrapper);
        ArrayList<SysPermissionVo> sysPermissionVos = new ArrayList<>();
        for (SysPermissionPo permissionPo : page.getRecords()) {
            SysPermissionVo sysPermissionVo = permissionPoToVo(permissionPo);
            List<Integer> roleIds = sysRolePermissionMapper.selectList(new LambdaQueryWrapper<>(SysRolePermissionPo.class).eq(SysRolePermissionPo::getPermissionId, permissionPo.getId())).stream().map(SysRolePermissionPo::getRoleId).toList();
            sysPermissionVo.setRoleIds(roleIds);
            sysPermissionVos.add(sysPermissionVo);
        }
        return new PageBean<>(page, sysPermissionVos);
    }

    @Override
    @Transactional
    public void bindingRole(SysPermissionBindingRoleDto sysPermissionBindingRoleDto) throws SysRoleException, SysPermissionException {
        // 检查权限存在性
        SysPermissionPo sysPermissionPo = permissionNotExistsThrow(sysPermissionBindingRoleDto.getPermissionId());
        // 检查角色存在性
        roleNotExistsThrow(sysPermissionBindingRoleDto.getRoleId());
        // 检查是否以及绑定
        if (sysRolePermissionMapper.exists(new LambdaQueryWrapper<>(SysRolePermissionPo.class)
                .eq(SysRolePermissionPo::getRoleId, sysPermissionBindingRoleDto.getRoleId())
                .eq(SysRolePermissionPo::getPermissionId, sysPermissionBindingRoleDto.getPermissionId())))
            throw new SysPermissionException(SysPermissionException.RELATION_HAS_EXISTS);
        // 绑定权限
        sysRolePermissionMapper.insert(BeanUtil.copyProperties(sysPermissionBindingRoleDto, SysRolePermissionPo.class));
        // 将关系添加到redis
        redisComponent.setRP_Relation(sysPermissionBindingRoleDto.getRoleId(),
                sysPermissionPo.getAuthCode(), sysPermissionBindingRoleDto.getPermissionId());
    }

    @Override
    @Transactional
    public void unbindingRole(SysPermissionBindingRoleDto sysPermissionBindingRoleDto) throws SysPermissionException {
        // 检查权限存在性
        SysPermissionPo sysPermissionPo = permissionNotExistsThrow(sysPermissionBindingRoleDto.getPermissionId());
        int delete = sysRolePermissionMapper.delete(new LambdaQueryWrapper<>(SysRolePermissionPo.class)
                .eq(SysRolePermissionPo::getRoleId, sysPermissionBindingRoleDto.getRoleId())
                .eq(SysRolePermissionPo::getPermissionId, sysPermissionBindingRoleDto.getPermissionId()));
        if (delete == 0)
            throw new SysPermissionException(SysPermissionException.RELATION_NOT_EXISTS);
        // 将redis关系删除
        redisComponent.removeRP_Relation(sysPermissionBindingRoleDto.getRoleId(), sysPermissionPo.getAuthCode());
    }

    @Override
    @Transactional
    public void modifyStatus(Integer permissionId) throws SysPermissionException {
        SysPermissionPo sysPermissionPo = permissionNotExistsThrow(permissionId);
        SysPermissionStatusEnum newStatus = SysPermissionStatusEnum.VERIFY;
        if (Objects.requireNonNull(SysPermissionStatusEnum.getByCode(sysPermissionPo.getStatus()))
                .equals(SysPermissionStatusEnum.VERIFY))
            newStatus = SysPermissionStatusEnum.NOT_VERIFY;
        sysPermissionMapper.update(new LambdaUpdateWrapper<>(SysPermissionPo.class)
                .set(SysPermissionPo::getStatus, newStatus.getCode())
                .eq(SysPermissionPo::getId, permissionId));
        // 修改redis状态
        redisComponent.setPermission(sysPermissionPo.getAuthCode(), newStatus.getCode());
    }

    private SysPermissionPo permissionNotExistsThrow(Integer permissionId) throws SysPermissionException {
        SysPermissionPo sysPermissionPo = sysPermissionMapper.selectOne(new LambdaQueryWrapper<>(SysPermissionPo.class).eq(SysPermissionPo::getId, permissionId));
        if (Objects.isNull(sysPermissionPo))
            throw new SysPermissionException(SysPermissionException.PERMISSION_NOT_EXISTS);
        return sysPermissionPo;
    }

    private SysRolePo roleNotExistsThrow(Integer roleId) throws SysRoleException {
        SysRolePo sysRolePo = sysRoleMapper.selectOne(new LambdaQueryWrapper<>(SysRolePo.class).eq(SysRolePo::getId, roleId));
        if (Objects.isNull(sysRolePo))
            throw new SysRoleException(SysRoleException.ROLE_NOT_EXISTS);
        return sysRolePo;
    }

    private SysPermissionVo permissionPoToVo(SysPermissionPo sysPermissionPo) {
        SysPermissionVo sysPermissionVo = BeanUtil.copyProperties(sysPermissionPo, SysPermissionVo.class);
        return sysPermissionVo;
    }
}
